/*******************************************************************************
 ** Name: team.cpp                                                             **
 ** Description:                         **
 **                                                                           **
 ** Open Source Initiative (OSI) Approved License                             **
 **                                                                           **
 ** The contents of this file are subject to the terms of the                 **
 ** Common Development and Distribution License, Version 1.0 only             **
 ** (the "License").  You may not use this file except in compliance          **
 ** with the License.                                                         **
 **                                                                           **
 ** You can find a copy of the license in the LICENSE file within             **
 ** this distribution or at $WIKI/display/ODS/License-software.              **
 ** Software distributed under the License is distributed on an "AS IS"       **
 ** basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.           **
 ** See the License for the specific language governing permissions           **
 ** and limitations under the License.                                        **
 **                                                                           **
 ** When distributing Covered Code, include this CDDL header in each          **
 ** file and include the License file at $GAME_DIR/LICENSE.                   **
 ** If applicable, add the following below this header, with the indicated    **
 ** fields enclosed by brackets "[]" replaced with your own identifying       **
 ** information: Portions Copyright [yyyy] [name of copyright owner]          **
 **                                                                           **
 ** Copyright (c) 2009-2012 Open Design Strategies, LLC                       **
 ** All rights reserved.                                                      **
 ******************************************************************************/
// $HeadURL$
// Modified $Date$ by $Author$
// $Id$

#include "team.hpp"

/////////////////////////////////////[ Team
Team::Team()
{
	_formation = Formation::Default;
	// Create a new channel for this team
	_channel = channel::Create();
	_channel->Name(global::UUIDFactory::Create());
}

Team::Team(const std::string & n)
{
	_formation = Formation::Default;
	_channel = channel::Create(n);
}

void
Team::AddMember(Character::pointer m)
{
	if (_members.size() >= MAX_TEAM_MEMBERS)
		return;
	// Figure out what position they fall into
	Member newMember;
	newMember.member = m;
	newMember.pos = TeamPosition::empty;

	_members.push_back(newMember);
	_channel->join(m);

	std::ostringstream ss;
	ss << m->Name() << " has joined the team.";
	SendToTeamChannel(ss.str().data());
}

void
Team::RemoveMember(Character::pointer m)
{
	// Algo:
	// 1. if we're leader and we're not the last one on the team
	//    assign team leader to the next in the team roster
	// 2. formally remove the character from the member roster
	//    and team channel
	// if we're removing the leader, make new leader
	// @NB this may not work since the initial team_leader will have
	// the originally allocated team object and will be deleted when
	// the reference count on it goes to zero.
	if (_leader->ID() == m->ID())
	{
		if (_members.size() > 1)
		{
			_leader = _members.front().member;
			// notify the team that there is a new teamleader
			std::ostringstream ss;
			ss << _leader->Codename() << " has been made team leader.";
			SendToTeamChannel(ss.str().data());
		} else {
			// just return. the channel and member lists will get release
			// when we null our _team object
			SendToTeamChannel("You have dissolved your team.");
			return;
		}
	}
	// ok so now formally remove the member from the team roster and channel
	std::vector<Member>::iterator i;
	for(i = _members.begin(); i != _members.end(); ++i)
	{
		if ((*i).member->ID() == m->ID())
		{
			_members.erase(i);
			_channel->leave(m);
			std::ostringstream ss;
			ss << m->Codename() << " has quit the team.";
			SendToTeamChannel(ss.str().data());
		}
	}
}

void
Team::SetFormation(Formation f)
{
	_formation = f;
	_assign_member_positions();
}

void
Team::SendToTeamChannel(const char * m)
{
	std::ostringstream ss;
	ss << "<faction>" << _channel->Name() << ">" << m << "</faction>" << std::endl;
	_channel->deliver(ss.str());
}

void
Team::_assign_member_positions()
{
	int row = 0, col = 0;
	std::vector<Member>::iterator i;
	for(i = _members.begin(); i != _members.end(); ++i)
	{
		if ((*i).pos == TeamPosition::empty)
		{
			// assign a position
			switch(_formation)
			{
			case Formation::Default:
				(*i).pos = _get_next_available_position(FormationDefault,row,col);
				break;
			case Formation::Aegis:
				(*i).pos = _get_next_available_position(FormationAegis,row,col);
				break;
			case Formation::Tower:
				(*i).pos = _get_next_available_position(FormationTower,row,col);
				break;
			case Formation::Snare:
				(*i).pos = _get_next_available_position(FormationSnare,row,col);
				break;
			case Formation::Point:
				(*i).pos = _get_next_available_position(FormationPoint,row,col);
				break;
			case Formation::Wedge:
				(*i).pos = _get_next_available_position(FormationWedge,row,col);
				break;
			case Formation::Banana:
				(*i).pos = _get_next_available_position(FormationBanana,row,col);
				break;
			}
		}
	}

}

TeamPosition
Team::_get_next_available_position(const TeamPosition tp[5][5], int & r, int & c)
{
	for (; r < 5; r++)
	{
		for (; c < 5; c++)
		{
			if (tp[r][c] != TeamPosition::empty)
				return tp[r][c];

			if (c == 5) c = 0;
		}
	}
	return TeamPosition::empty;
}

void
Team::AssignPosition(const std::string & c, TeamPosition t)
{
	if (t == TeamPosition::empty)
	{
		// we're removing someone's position, but keeeping them on the team
		std::vector<Member>::iterator i;
		for (i = _members.begin(); i != _members.end(); ++i)
		{
			if ((*i).member->Codename() == c)
			{
				(*i).pos = TeamPosition::empty;
				return;
			}
		}
	}
	// check position
	if (_is_position_taken(t))
	{
		// maybe we should notify the team?
		SendToTeamChannel("That position is already taken.");
		return;
	}

	std::vector<Member>::iterator i;
	for(i = _members.begin(); i != _members.end(); ++i)
	{
		if ((*i).member->Codename() == c)
		{
			(*i).pos = t;
			return;
		}
	}

}

bool
Team::_is_position_taken(TeamPosition t)
{
	std::vector<Member>::iterator i;
	for(i = _members.begin(); i != _members.end(); ++i)
	{
		if ((*i).pos == t)
		{
			return true;
		}
	}
	return false;
}

